package cheme.ProcessModel.Cmds;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.gef.commands.Command;

import cheme.ProcessModel.IModelElement;

public abstract  class ChemeCommand extends Command implements IChemeCommand
{
	protected IModelElement source = null;

	private List<Command> preList = new ArrayList<Command>();

	private List<Command> postList = new ArrayList<Command>();

	public ChemeCommand(Object source)
	{
		super();
		setSource((IModelElement)source);
	}

	protected abstract void primExecute();
	protected abstract void primUndo();
	
	protected void primRedo()
	{
		primExecute();
	}
	

	public ChemeCommand(Object source, String label)
	{
		super(label);
		setSource((IModelElement)source);
	}

	public IModelElement getSource()
	{
		return source;
	}

	public void setSource(IModelElement source)
	{
		this.source = source;
	}

	public void prefix(Command command)
	{
		getPreCommands().add(0, command);
	}
	
	/**
	 * Adds the specified command if it is not <code>null</code>.
	 * 
	 * @param command
	 *            <code>null</code> or a Command
	 */
	public void append(Command command)
	{
		if(command != null)
		{
			getPostCommands().add(command);
		}
	}

	/**
	 * Disposes all contained Commands.
	 * 
	 * @see org.eclipse.gef.commands.Command#dispose()
	 */
	public void dispose()
	{
		for(int i = 0; i < getPreCommands().size(); i++)
		{
			getPreCommands().get(i).dispose();
		}
		
		for(int i = 0; i < getPostCommands().size(); i++)
		{
			getPostCommands().get(i).dispose();
		}
	}

	/**
	 * Execute the command.For a compound command this means executing all of
	 * the commands that it contains.
	 */
	public void execute()
	{
		Command cmd = null;
				
		for(int i = 0; i < getPreCommands().size(); i++)
		{
			cmd = getPreCommands().get(i);
			try
			{
				cmd.execute();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		
		primExecute();
		
		for(int i = 0; i < getPostCommands().size(); i++)
		{
			cmd = getPostCommands().get(i);
			try
			{
				cmd.execute();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	public void redo()
	{
		Command cmd = null;
				
		for(int i = 0; i < getPreCommands().size(); i++)
		{
			cmd = getPreCommands().get(i);
			try
			{
				cmd.execute();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		
		primRedo();
		
		for(int i = 0; i < getPostCommands().size(); i++)
		{
			cmd = getPostCommands().get(i);
			try
			{
				cmd.execute();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}

	/**
	 * @return the List of contained pre Commands
	 */
	public List<Command> getPreCommands()
	{
		return preList;
	}

	/**
	 * @return the List of contained post Commands
	 */
	public List<Command> getPostCommands()
	{
		return postList;
	}

	/**
	 * @return <code>true</code> if the CompoundCommand is empty
	 */
	public boolean isEmpty()
	{
		return getPreCommands().isEmpty() && getPostCommands().isEmpty();
	}

	/**
	 * @see org.eclipse.gef.commands.Command#undo()
	 */
	public void undo()
	{
		for(int i = getPostCommands().size() - 1; i >= 0; i--)
		{
			try
			{
				getPostCommands().get(i).undo();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
				
		primUndo();
		
		for(int i = getPreCommands().size() - 1; i >= 0; i--)
		{
			try
			{
				getPreCommands().get(i).undo();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
}
